﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using FFShellAPI.FFMPEG.Settings;

namespace AVCWizard
{
    /// <summary>
    /// Interaktionslogik für CuttingTool.xaml
    /// </summary>
    public partial class CuttingTool : UserControl, INotifyPropertyChanged
    {
        double maxPosition = 0d;
        double minPosition = 0d;
        double startPosition = 0d;
        double endPosition = 0d;
        bool sliderFrontCapMove = false;
        bool sliderEndCapMove = false;
        Point sliderFrontOffset;
        Point sliderEndOffset;
        double rangeOffset;
        RangeSettings range;
        TimeSpan timeLength;

        public CuttingTool()
        {
            InitializeComponent();
            range = new RangeSettings();
            TimeLength = new TimeSpan(0, 10, 0);
        }

        public double StartPosition
        {
            get { return startPosition; }
            set
            {
                startPosition = (value < minPosition) ? minPosition : (value > maxPosition) ? maxPosition : value;
                OnPropertyChanged("StartPosition");
            }
        }

        public double EndPosition
        {
            get { return endPosition; }
            set
            {
                endPosition = (value < minPosition) ? minPosition : (value > maxPosition) ? maxPosition : value;
                OnPropertyChanged("EndPosition");
            }
        }

        public TimeSpan Duration
        {
            get { return GetEndTime() - GetStartTime(); }
        }

        public TimeSpan TimeLength 
        {
            get { return timeLength; } 
            set
            {
                timeLength = value;
                range.Position = new TimeStamp();
                range.Duration = new TimeStamp(timeLength);
            }
        }

        public RangeSettings Range
        {
            get
            {
                RangeSettings rs = new RangeSettings();
                rs.Position = range.Position;
                rs.Duration = range.Duration;
                return rs;
            }
        }

        private static double SecondsFromTimeSpan(TimeSpan time)
        {
            double dtime = time.Hours * 3600d + time.Minutes * 60d + time.Seconds;
            return dtime;
        }

        private void SetStartTime(TimeSpan value)
        {
            double s = SecondsFromTimeSpan(TimeLength);
            double v = SecondsFromTimeSpan(value);
            StartPosition = (maxPosition - minPosition) * v / s;
        }

        private void SetEndTime(TimeSpan value)
        {
            double s = SecondsFromTimeSpan(TimeLength);
            double v = SecondsFromTimeSpan(value);
            EndPosition = (maxPosition - minPosition) * (1d - v / s);
        }

        public void SetRange(RangeSettings range)
        {
            SetStartTime(range.Position.TimeSpanValue);
            SetEndTime(range.Position.TimeSpanValue + range.Duration.TimeSpanValue);
            UpdateData(false);
        }

        public void Reset()
        {
            range.Position = TimeStamp.Zero;
            range.Duration = TimeStamp.FromTimeSpan(TimeLength);
            SetRange(range);
            UpdateData(true);
        }

        private TimeSpan GetStartTime()
        {
            double v = StartPosition / (maxPosition - minPosition);
            if (v > 0.99d) v = 1d;
            if (v < 0.02d) v = 0d;
            double s = SecondsFromTimeSpan(TimeLength);
            return TimeSpan.FromSeconds(s * v);
        }

        private TimeSpan GetEndTime()
        {
            double v = 1d - EndPosition / (maxPosition - minPosition);
            if (v > 0.99d) v = 1d;
            if (v < 0.02d) v = 0d;
            double s = SecondsFromTimeSpan(TimeLength);
            return TimeSpan.FromSeconds(s * v);
        }

        public double RangeOffset
        {
            get { return rangeOffset; }
            set 
            { 
                rangeOffset = value;
                UpdateRange();
            }
        }

        private void UpdateRange()
        {
            maxPosition = ActualWidth - rangeOffset;
            minPosition = rangeOffset;
            StartPosition = startPosition;
            EndPosition = endPosition;
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            RangeOffset = 8d;
            UpdateData(false);
        }

        private void UserControl_MouseUp(object sender, MouseButtonEventArgs e)
        {
            sliderFrontCapMove = false;
            sliderEndCapMove = false;
            LeftCapToolTip.IsOpen = false;
            RightCapToolTip.IsOpen = false;
            Mouse.Capture(null);
        }

        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            UpdateRange();
            SetRange(range);
        }

        private void updateToolTip(ToolTip t, Point pos, string text)
        {
            Point screen = PointToScreen(pos);
            Point locationFromWindow = SliderFrontCap.TranslatePoint(new Point(0, 0), this);
            screen.Y = PointToScreen(locationFromWindow).Y;
            t.HorizontalOffset = screen.X;
            t.VerticalOffset = screen.Y;
            t.Content = text;
        }

        private void UserControl_MouseMove(object sender, MouseEventArgs e)
        {
            UpdateRange();
            if (sliderFrontCapMove)
            {
                Point pos = e.GetPosition(this);
                pos.X -= sliderFrontOffset.X;
                StartPosition = pos.X;
                pos.X = StartPosition;
                updateToolTip(LeftCapToolTip, pos, GetStartTime().ToShortTimeString());
                UpdateData(true);
            }
            if (sliderEndCapMove)
            {
                Point pos = e.GetPosition(this);
                pos.X = ActualWidth - (pos.X - sliderEndOffset.X);
                EndPosition = pos.X;
                pos.X = ActualWidth - EndPosition;
                updateToolTip(RightCapToolTip, pos, GetEndTime().ToShortTimeString());
                UpdateData(true);
            }
        }

        private void UpdateData(bool bEvent)
        {
            if (Duration.TotalSeconds < 0d)
            {
                SetRange(range);
            }
            DurationLabel.Content = Duration.ToShortTimeString();
            range.Position = new TimeStamp(GetStartTime());
            range.Duration = new TimeStamp(Duration);
            if (bEvent && RangeChanged != null) 
                RangeChanged(this, null);
        }

        private void SliderFrontCap_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            sliderFrontOffset = e.GetPosition(SliderFrontCap);
            sliderFrontCapMove = true;
            LeftCapToolTip.IsOpen = true;
            Mouse.Capture(this);
        }

        private void SliderEndCap_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            sliderEndOffset = e.GetPosition(SliderEndCap);
            sliderEndCapMove = true;
            RightCapToolTip.IsOpen = true;
            Mouse.Capture(this);
        }

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }

        public event EventHandler RangeChanged;
        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class DoubleToGridLengthConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            double val = (double)System.Convert.ChangeType(value, typeof(System.Double));
            return new GridLength(val);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            double val = ((GridLength)value).Value;
            return val;
        }
    }
}
